package com.ywk.base.java8.optional;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 参考连接：https://zhuanlan.zhihu.com/p/40966718
 * 注意点：https://juejin.cn/post/7162882431932956680
 * @author zbh
 * @date 2022/9/16 11:28
 */
public class OptionalTest {


    private static List<User> userList = new ArrayList<>();

    static {
        userList.add(new User("1",22, "王旭","3",8000));
        userList.add(new User("2",21, "孙萍" ,"5",6000));
        userList.add(new User("3",23, "步传宇","1",10000));
        userList.add(new User("4",18, "蔡明浩","3",8500));
        userList.add(new User("5",17, "郭林杰","4",7000));
        userList.add(new User("6",29, "韩凯","4",12000));
        userList.add(new User("7",22, "韩天琪","2",20000));
        userList.add(new User("8",21, "郝玮","3",15000));
        userList.add(new User("9",19, "胡亚强","2",10000));
        userList.add(new User("10",14, "季恺","1",9000));
        userList.add(new User("11",17, "荆帅","5",8500));
        userList.add(new User("12",16, "姜有琪","1",10000));
    }

    public static void main(String[] args) {
        User user = new User("0", 26, "ywk", "0", 10000);
        //基本API
        /**
         * 1.构造 Optional方式：
         * 1）Optional.of(T value)，该方法通过一个非 null 的 value 来构造一个 Optional，传入的参数一定不能为 null，否则便会抛出 NullPointerException。
         * 2）Optional.ofNullable(T value)，该方法和 of 方法的区别在于传入的参数可以为 null
         * 3）Optional.empty()，该方法用来构造一个空的 Optional
         */

        //2. ifPresent()`判断是否存在对象，存在则执行 ifPresent() 方法里的函数
        System.out.println("=====================Optional.ifPresent()========================");
        Optional<User> op1 = Optional.ofNullable(user);
        op1.ifPresent(op ->System.out.println("Username is: " + op.getName()));

        //3.orElse：如果 Optional 中有值则将其返回，否则返回 orElse 方法传入的参数。
        System.out.println("=====================Optional.orElse()========================");
        System.out.println(Optional.ofNullable(user).orElse(new User("00", "yyy")));
        System.out.println(Optional.ofNullable(null).orElse(new User("00", "yyy")));

        //4.orElseGet：与 orElse类似，区别在于 orElseGet 方法传入的参数为一个 Supplier 接口的实现即函数
        System.out.println("=====================Optional.orElseGet()========================");
        System.out.println(Optional.ofNullable(user).orElseGet(()->new User("00", "yyy")));
        System.out.println(Optional.ofNullable(null).orElseGet(()->new User("00", "yyy")));

        //5.orElseThrow：与 orElse类似，区别在于 orElseThrow 方法当 Optional 中有值的时候，返回值；没有值的时候会抛出异常，抛出的异常由传入的 exceptionSupplier 提供
        /**
         * 适用场景：举一个 orElseThrow 的用途：在 SpringMVC 的控制器中，我们可以配置统一处理各种异常。查询某个实体时，如果数据库中
         * 有对应的记录便返回该记录，否则就可以抛出 EntityNotFoundException ，处理 EntityNotFoundException 的方法中我们就给客
         * 户端返回Http 状态码 404 和异常对应的信息 —— orElseThrow 完美的适用于这种场景。
         */
        System.out.println("=====================Optional.orElseThrow()========================");
//        System.out.println(Optional.ofNullable(null).orElseThrow(()->null).toString());


        //6.map：如果当前 Optional 为 Optional.empty，则依旧返回 Optional.empty；否则返回一个新的以函数 value 作为输入输出值的 Optional
        System.out.println("=====================Optional.map()========================");
        System.out.println(Optional.ofNullable(user).map(u -> u.getName()).map(name -> name.toUpperCase()));

        //7. flatMap：与 map 方法的区别在于flatMap 要求参数中的函数的输出的就是 Optional
        System.out.println("=====================Optional.flatMap()========================");
        System.out.println(Optional.ofNullable(user).flatMap(u -> Optional.of(u.getName())).flatMap(name -> Optional.of(name.toUpperCase())));

        //8.filter：filter 方法接受一个 Predicate 来对 Optional 中包含的值进行过滤，如果包含的值满足条件，那么还是返回这个 Optional；否则返回 Optional.empty
        System.out.println("=====================Optional.filter()========================");
        Optional.ofNullable(user).filter(u->u.getAge()>18).ifPresent(u-> System.out.println(u));

        //（Java9 在 Optional 类中添加了三个新的方法：or(),ifPresentOrElse(),stream()）
        System.out.println("======================基本API END=======================");

        System.out.println("======================案例1：获取年龄大于 18 岁对象集合=======================");
        // 1. 获取年龄大于 18 岁对象集合
        List<User> res=new ArrayList<>();
        //方式1（get()：获取optional实例中的对象，当optional 容器为空时报错）
        res = Optional.ofNullable(OptionalTest.userList)
                .get()
                .stream()
                .filter(u -> u.getAge() > 18)
                .collect(Collectors.toList());
        //方式2
        /*res = list.stream()
                .filter(i -> i.getAge()>18)
                .collect(Collectors.toList());*/
        System.out.println(res);

        //金典用法【嵌套的if判空】
        user.setCard(new Card(0,"0"));
        Card card = Optional.ofNullable(user)
                .map(User::getCard)
                .orElse(new Card(-0,"-1"));
        System.out.println(card);
    }
}

